// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

// ****************************************************************************
//  File: ExplodeViewerEnginePluginInfo.C
// ****************************************************************************

#include <ExplodePluginInfo.h>
#include <ExplodeAttributes.h>

//
// Storage for static data elements.
//
ExplodeAttributes *ExplodeViewerEnginePluginInfo::clientAtts = NULL;
ExplodeAttributes *ExplodeViewerEnginePluginInfo::defaultAtts = NULL;

// ****************************************************************************
//  Method:  ExplodeViewerEnginePluginInfo::InitializeGlobalObjects
//
//  Purpose:
//    Initialize the operator atts.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************
void
ExplodeViewerEnginePluginInfo::InitializeGlobalObjects()
{
    if (ExplodeViewerEnginePluginInfo::clientAtts == NULL)
    {
        ExplodeViewerEnginePluginInfo::clientAtts  = new ExplodeAttributes;
        ExplodeViewerEnginePluginInfo::defaultAtts = new ExplodeAttributes;
    }
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::GetClientAtts
//
//  Purpose:
//    Return a pointer to the viewer client attributes.
//
//  Returns:    A pointer to the viewer client attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

AttributeSubject *
ExplodeViewerEnginePluginInfo::GetClientAtts()
{
    return clientAtts;
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::GetDefaultAtts
//
//  Purpose:
//    Return a pointer to the viewer default attributes.
//
//  Returns:    A pointer to the viewer default attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

AttributeSubject *
ExplodeViewerEnginePluginInfo::GetDefaultAtts()
{
    return defaultAtts;
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::SetClientAtts
//
//  Purpose:
//    Set the viewer client attributes.
//
//  Arguments:
//    atts      A pointer to the new client attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

void
ExplodeViewerEnginePluginInfo::SetClientAtts(AttributeSubject *atts)
{
    *clientAtts = *(ExplodeAttributes *)atts;
    clientAtts->Notify();
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::GetClientAtts
//
//  Purpose:
//    Get the viewer client attributes.
//
//  Arguments:
//    atts      A pointer to return the client default attributes in.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

void
ExplodeViewerEnginePluginInfo::GetClientAtts(AttributeSubject *atts)
{
    *(ExplodeAttributes *)atts = *clientAtts;
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::InitializeOperatorAtts
//
//  Purpose:
//    Initialize the operator attributes to the default attributes.
//
//  Arguments:
//    atts        The attribute subject to initialize.
//    plot        The viewer plot that owns the operator.
//    fromDefault True to initialize the attributes from the defaults. False
//                to initialize from the current attributes.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
//  Modifications:
//
//      Alister Maguire, Wed Nov  8 10:12:34 PST 2017
//      Added retrieval of boundary names.
//
//      Alister Maguire, Wed Jan 17 15:28:46 PST 2018
//      Moved most of the method to PrivateSetOperatorAtts().
//
// ****************************************************************************
#include <avtPlotMetaData.h>

void
ExplodeViewerEnginePluginInfo::InitializeOperatorAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot, const bool fromDefault)
{
    if (fromDefault)
        *(ExplodeAttributes*)atts = *defaultAtts;
    else
        *(ExplodeAttributes*)atts = *clientAtts;

    PrivateSetOperatorAtts(atts, plot);
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::UpdateOperatorAtts
//
//  Purpose:
//    Update the operator attributes when using operator expressions.
//
//  Arguments:
//    atts        The attribute subject to update.
//    plot        The viewer plot that owns the operator.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
//  Modifications:
//      Alister Maguire, Wed Jan 17 15:28:46 PST 2018
//      Added a call to PrivateSetOperatorAtts().
//
// ****************************************************************************

void
ExplodeViewerEnginePluginInfo::UpdateOperatorAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot)
{
    cerr << "UPDATING OPERATOR ATTS" << endl;
    *(ExplodeAttributes*)atts = *defaultAtts;

    PrivateSetOperatorAtts(atts, plot);
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::GetMenuName
//
//  Purpose:
//    Return a pointer to the name to use in the viewer menus.
//
//  Returns:    A pointer to the name to use in the viewer menus.
//
//  Programmer: generated by xml2info
//  Creation:   omitted
//
// ****************************************************************************

const char *
ExplodeViewerEnginePluginInfo::GetMenuName() const
{
    return "Explode";
}

// ****************************************************************************
//  Method: ExplodeViewerEnginePluginInfo::PrivateSetOperatorAtts
//
//  Purpose:
//      Retrieve the boundary (material) names and set them within the i
//      operator attributes.
//
//  Programmer: Alister Maguire
//  Creation:   Wed Jan 17 15:28:46 PST 2018
//
//  Modifications:
//
//      Alister Maguire, Tue Sep 18 14:57:03 PDT 2018
//      Added the ability to handle multiple types of subsets.
//
// ****************************************************************************

#include <set>

#include <DebugStream.h>
#include <InvalidVariableException.h>

void
ExplodeViewerEnginePluginInfo::PrivateSetOperatorAtts(AttributeSubject *atts,
    const avtPlotMetaData &plot)
{
    ExplodeAttributes *explodeAtts = (ExplodeAttributes *)atts;

    const avtMaterialMetaData *mat = NULL;
    const avtDatabaseMetaData *md  = plot.GetMetaData();
    if (md == NULL)
    {
        return;
    }

    std::string  varName(plot.GetVariableName());
    std::string  meshName = md->MeshForVar(varName);
    avtMeshMetaData *mesh =
        const_cast <avtMeshMetaData *> (md->GetMesh(meshName));
    stringVector subsetNames;
    stringVector::const_iterator pos;
    char temp[512];

    //
    // Create subset names, based on Subset Type
    //
    avtSubsetType subT = md->DetermineSubsetType(varName);
    switch (subT)
    {
        case AVT_DOMAIN_SUBSET :
        {
            debug5 << "Exploding a domain mesh subset." << endl;
            explodeAtts->SetSubsetType(ExplodeAttributes::Domain);
            defaultAtts->SetSubsetType(ExplodeAttributes::Domain);
            if (mesh->blockNames.empty())
            {
                for (int i = 0; i < mesh->numBlocks; i++)
                {
                    sprintf(temp, "%d", i+mesh->blockOrigin);
                    subsetNames.push_back(temp);
                }
            }
            else
            {
                for(pos = mesh->blockNames.begin();
                    pos != mesh->blockNames.end(); ++pos)
                {
                    subsetNames.push_back(*pos);
                }
            }
        }
        break;

        case AVT_GROUP_SUBSET :
        {
            debug5 << "Exploding a group mesh subset." << endl;
            explodeAtts->SetSubsetType(ExplodeAttributes::Group);
            defaultAtts->SetSubsetType(ExplodeAttributes::Group);

            std::set<int>    groupSet;
            std::vector<int> gIDS;

            if (!mesh->groupNames.empty())
            {
                for (size_t i = 0; i < mesh->groupNames.size(); ++i)
                {
                    subsetNames.push_back(mesh->groupNames[i]);
                }
            }
            else if (mesh->groupIds.size() > 0)
            {
                for (size_t i = 0; i < mesh->groupIds.size(); i++)
                {
                    if (groupSet.count(mesh->groupIds[i]) == 0)
                    {
                        groupSet.insert(mesh->groupIds[i]);
                        gIDS.push_back(mesh->groupIds[i]);
                    }
                }
                for (size_t i = 0; i < gIDS.size(); i++)
                {
                    sprintf(temp, "%d", gIDS[i]);
                    subsetNames.push_back(temp);
                }
            }
            else
            {
                int origin = mesh->groupOrigin;
                int nGroups = (int)mesh->groupIdsBasedOnRange.size()-1;
                for (int i = 0; i < nGroups; i++)
                {
                    groupSet.insert(origin+i);
                    gIDS.push_back(origin+i);
                    sprintf(temp, "%d", origin+i);
                    subsetNames.push_back(temp);
                }
            }
        }
        break;

        case AVT_ENUMSCALAR_SUBSET :
        {
            debug5 << "Exploding an enumerated scalar subset." << endl;
            explodeAtts->SetSubsetType(ExplodeAttributes::EnumScalar);
            defaultAtts->SetSubsetType(ExplodeAttributes::EnumScalar);
            const avtScalarMetaData *smd = md->GetScalar(varName);
            if (smd != NULL)
            {
                for(pos = smd->enumNames.begin();
                    pos != smd->enumNames.end(); ++pos)
                {
                    subsetNames.push_back(*pos);
                }
            }
        }
        break;

        case AVT_MATERIAL_SUBSET:
        // Fall through to default

        default:
        {
            //
            // By default, we explode materials.
            //
            debug5 << "Exploding a materials." << endl;
            int numMaterials = md->GetNumMaterials();
            explodeAtts->SetSubsetType(ExplodeAttributes::Material);
            defaultAtts->SetSubsetType(ExplodeAttributes::Material);

            for (int i = 0; i < numMaterials; ++i)
            {
                mat = md->GetMaterial(i);
                if (mat != NULL)
                {
                    for (pos = mat->materialNames.begin();
                         pos != mat->materialNames.end(); ++pos)
                    {
                        if ( !(*pos).empty() )
                        {
                            subsetNames.push_back(*pos);
                        }
                    }
                }
                mat = NULL;
            }
        }
        break;
    }

    explodeAtts->SetBoundaryNames(subsetNames);
    defaultAtts->SetBoundaryNames(subsetNames);
}

